package cn.sunxiansheng.redis.utils;

import org.springframework.data.redis.core.RedisTemplate;

import java.util.*;

/**
 * Description: Redis的Hash类型操作
 *
 * @Author sun
 * @Create 2024/11/14 14:50
 * @Version 1.1
 */
public class RHash extends RBase {

    /**
     * 构造器给父类注入RedisTemplate
     *
     * @param redisTemplate RedisTemplate实例
     */
    public RHash(RedisTemplate<String, Object> redisTemplate) {
        super(redisTemplate);
    }

    /**
     * 设置单个hash值
     *
     * @param key       key
     * @param hashKey   hashKey
     * @param hashValue hashValue
     */
    public void put(String key, String hashKey, Object hashValue) {
        redisTemplate.opsForHash().put(key, hashKey, hashValue);
    }

    /**
     * 设置多个hash值
     *
     * @param key key
     * @param map map
     */
    public void putAll(String key, Map<String, ?> map) {
        if (map == null || map.isEmpty()) {
            throw new IllegalArgumentException("Map不能为空！");
        }
        redisTemplate.opsForHash().putAll(key, map);
    }

    /**
     * 删除hash中的一些值
     *
     * @param key      key
     * @param hashKeys hashKeys
     * @return 删除的个数
     */
    public Long delete(String key, List<String> hashKeys) {
        if (hashKeys == null || hashKeys.isEmpty()) {
            return 0L;
        }
        return redisTemplate.opsForHash().delete(key, hashKeys.toArray());
    }

    /**
     * 删除hash中的一个值
     *
     * @param key     key
     * @param hashKey hashKey
     * @return 删除的个数
     */
    public Long delete(String key, String hashKey) {
        if (hashKey == null) {
            return 0L;
        }
        return redisTemplate.opsForHash().delete(key, hashKey);
    }

    /**
     * 获取单个hash值，并转换为指定类型
     *
     * @param key     key
     * @param hashKey hashKey
     * @param type    类型
     * @param <T>     要转换的类型
     * @return hash值
     */
    public <T> T getOneMapValue(String key, String hashKey, Class<T> type) {
        if (hashKey == null) {
            return null;
        }
        Object object = redisTemplate.opsForHash().get(key, hashKey);
        return convertValue(object, type);
    }

    /**
     * 获取多个hash值，并转换为指定类型
     *
     * @param key      Redis键
     * @param hashKeys Hash键集合
     * @param type     转换的目标类型
     * @param <T>      返回的泛型类型
     * @return 转换后的Hash对象集合
     */
    public <T> List<T> getMultiMapValue(String key, Collection<String> hashKeys, Class<T> type) {
        if (hashKeys == null || hashKeys.isEmpty()) {
            return Collections.emptyList();
        }

        Collection<Object> keys = new ArrayList<>(hashKeys);
        List<Object> objects = redisTemplate.opsForHash().multiGet(key, keys);

        List<T> result = new ArrayList<>();
        for (Object obj : objects) {
            result.add(convertValue(obj, type));
        }
        return result;
    }

    /**
     * 获取所有键值对，并将其转换为指定类型
     *
     * @param key  键
     * @param type 返回值的类型
     * @param <T>  值类型
     * @return 转换后的Map，键为String类型，值为T类型
     */
    public <T> Map<String, T> getAll(String key, Class<T> type) {
        Map<Object, Object> entries = redisTemplate.opsForHash().entries(key);

        if (entries.isEmpty()) {
            return Collections.emptyMap();
        }

        Map<String, T> result = new HashMap<>();
        for (Map.Entry<Object, Object> entry : entries.entrySet()) {
            if (entry.getKey() instanceof String) {
                String strKey = (String) entry.getKey();
                T value = convertValue(entry.getValue(), type);
                result.put(strKey, value);
            } else {
                throw new ClassCastException("Redis中Hash的键不是String类型：实际类型为 " + entry.getKey().getClass().getName());
            }
        }
        return result;
    }

    /**
     * 判断hash中是否存在某个键
     *
     * @param key     key
     * @param hashKey hashKey
     * @return 是否存在
     */
    public Boolean hasHashKey(String key, String hashKey) {
        if (hashKey == null) {
            return false;
        }
        return redisTemplate.opsForHash().hasKey(key, hashKey);
    }
}